#ifndef LOG_H
#define LOG_H

#if defined(__cplusplus)
extern "C" {
#endif

#define LEVEL_TRACE 0
#define LEVEL_DEBUG 1
#define LEVEL_INFO 2
#define LEVEL_WARNING 3
#define LEVEL_ERROR 4
#define LEVEL_FATAL 5

typedef enum _LOG_LEVEL {
    LL_TRACE = LEVEL_TRACE,
    LL_DEBUG = LEVEL_DEBUG,
    LL_INFO = LEVEL_INFO,
    LL_WARNING = LEVEL_WARNING,
    LL_ERROR = LEVEL_ERROR,
    LL_FATAL = LEVEL_FATAL,
} LOG_LEVEL;

void log_write(LOG_LEVEL level, const char *format, ...);

#ifndef DEFAULT_LOG_LEVEL
#if defined(NDEBUG)
#define DEFAULT_LOG_LEVEL LEVEL_INFO
#else
#define DEFAULT_LOG_LEVEL LEVEL_DEBUG
#endif
#endif

#ifndef MINIMUM_LOG_LEVEL
#define MINIMUM_LOG_LEVEL DEFAULT_LOG_LEVEL
#endif

#if LEVEL_TRACE >= MINIMUM_LOG_LEVEL
#define LOG_T(MSG, ...) log_write(LL_TRACE, MSG, ##__VA_ARGS__)
#else
#define LOG_T(...)
#endif

#if LEVEL_DEBUG >= MINIMUM_LOG_LEVEL
#define LOG_D(MSG, ...) log_write(LL_DEBUG, MSG, ##__VA_ARGS__)
#else
#define LOG_D(...)
#endif

#if LEVEL_INFO >= MINIMUM_LOG_LEVEL
#define LOG_I(MSG, ...) log_write(LL_INFO, MSG, ##__VA_ARGS__)
#else
#define LOG_I(...)
#endif

#if LEVEL_WARNING >= MINIMUM_LOG_LEVEL
#define LOG_W(MSG, ...) log_write(LL_WARNING, MSG, ##__VA_ARGS__)
#else
#define LOG_W(...)
#endif

#if LEVEL_ERROR >= MINIMUM_LOG_LEVEL
#define LOG_E(MSG, ...) log_write(LL_ERROR, MSG, ##__VA_ARGS__)
#else
#define LOG_E(...)
#endif

#if LEVEL_FATAL >= MINIMUM_LOG_LEVEL
#define LOG_F(MSG, ...) log_write(LL_FATAL, MSG, ##__VA_ARGS__)
#else
#define LOG_F(...)
#endif

#if defined(__cplusplus)
}
#endif


#endif// LOG_H
